package org.codehaus.activemq.filter;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import javax.jms.JMSException;
import javax.jms.Message;

public class MultiExpressionEvaluator {
	HashMap rootExpressions;
	HashMap cachedExpressions;
	int view;

	public MultiExpressionEvaluator() {
		this.rootExpressions = new HashMap();
		this.cachedExpressions = new HashMap();

		this.view = 0;
	}

	public void addExpressionListner(Expression selector, ExpressionListener c) {
		ExpressionListenerSet data = (ExpressionListenerSet) this.rootExpressions.get(selector.toString());
		if (data == null) {
			data = new ExpressionListenerSet();
			data.expression = addToCache(selector);
			this.rootExpressions.put(selector.toString(), data);
		}
		data.listeners.add(c);
	}

	public boolean removeEventListner(String selector, ExpressionListener c) {
		String expKey = selector.toString();
		ExpressionListenerSet d = (ExpressionListenerSet) this.rootExpressions.get(expKey);
		if (d == null) {
			return false;
		}
		if (!d.listeners.remove(c)) {
			return false;
		}

		if (d.listeners.size() == 0) {
			removeFromCache((CacheExpression) d.expression);
			this.rootExpressions.remove(expKey);
		}
		return true;
	}

	private CacheExpression addToCache(Expression expr) {
		CacheExpression n = (CacheExpression) this.cachedExpressions.get(expr);
		if (n == null) {
			n = new CacheExpression(expr);
			this.cachedExpressions.put(expr, n);
			if ((expr instanceof UnaryExpression)) {
				UnaryExpression un = (UnaryExpression) expr;
				un.setRight(addToCache(un.getRight()));
			} else if ((expr instanceof BinaryExpression)) {
				BinaryExpression bn = (BinaryExpression) expr;
				bn.setRight(addToCache(bn.getRight()));
				bn.setLeft(addToCache(bn.getLeft()));
			}
		}
		CacheExpression tmp100_99 = n;
		tmp100_99.refCount = (short) (tmp100_99.refCount + 1);
		return n;
	}

	private void removeFromCache(CacheExpression cn) {
		CacheExpression tmp1_0 = cn;
		tmp1_0.refCount = (short) (tmp1_0.refCount - 1);
		Expression realExpr = cn.getRight();
		if (cn.refCount == 0) {
			this.cachedExpressions.remove(realExpr);
		}
		if ((realExpr instanceof UnaryExpression)) {
			UnaryExpression un = (UnaryExpression) realExpr;
			removeFromCache((CacheExpression) un.getRight());
		}
		if ((realExpr instanceof BinaryExpression)) {
			BinaryExpression bn = (BinaryExpression) realExpr;
			removeFromCache((CacheExpression) bn.getRight());
		}
	}

	public void evaluate(Message message) {
		Collection expressionListeners = this.rootExpressions.values();
		for (Iterator iter = expressionListeners.iterator(); iter.hasNext();) {
			ExpressionListenerSet els = (ExpressionListenerSet) iter.next();
			try {
				Object result = els.expression.evaluate(message);
				for (Iterator iterator = els.listeners.iterator(); iterator.hasNext();) {
					ExpressionListener l = (ExpressionListener) iterator.next();
					l.evaluateResultEvent(els.expression, message, result);
				}
			} catch (Throwable e) {
				Object result;
				Iterator iterator;
				e.printStackTrace();
			}
		}
	}

	static abstract interface ExpressionListener {
		public abstract void evaluateResultEvent(Expression paramExpression, Message paramMessage, Object paramObject);
	}

	static class ExpressionListenerSet {
		Expression expression;
		ArrayList listeners = new ArrayList();
	}

	public class CacheExpression extends UnaryExpression {
		short refCount = 0;
		int cview = MultiExpressionEvaluator.this.view - 1;
		Object cachedValue;
		int cachedHashCode;

		public CacheExpression(Expression realExpression) {
			super(realExpression);
			this.cachedHashCode = realExpression.hashCode();
		}

		public Object evaluate(Message message) throws JMSException {
			if (MultiExpressionEvaluator.this.view == this.cview) {
				return this.cachedValue;
			}
			this.cachedValue = this.right.evaluate(message);
			this.cview = MultiExpressionEvaluator.this.view;
			return this.cachedValue;
		}

		public int hashCode() {
			return this.cachedHashCode;
		}

		public boolean equals(Object o) {
			return ((CacheExpression) o).right.equals(this.right);
		}

		public String getExpressionSymbol() {
			return null;
		}

		public String toString() {
			return this.right.toString();
		}
	}
}